PROFDINFO.COM

Votre enseignant d'informatique en ligne

Section 3

Interaction avec les fichiers

Retour à la page du cours

Vous apprendrez aujourd'hui comment interagir avec les fichiers: les lire et y récupérer des données, puis y écrire pour produire un fichier de log par exemple.

L'écriture

Écrire dans un fichier n'est pas très compliquée. Il y a en effet un applet de commande prévu justement pour envoyer dans un fichier ce qu'il reçoit en entrée: out-file. Par exemple, essayez:

get-process | out-file -filepath processus.txt       	  

Notez qu'il n'est pas obligatoire d'écrire le -filepath, le premier paramètre est toujours considéré comme étant le chemin vers le fichier de destination:

get-process | out-file processus.txt       	  

Si on veut faire changer le format du tout, il faut faire attention. Ceci ne donne pas les résultats escomptés:

get-process | out-file processus.txt | format-list       	  

En effet, out-file ne produit pas de sortie, il envoie les données dans un fichier. Les données provenant de get-process seront donc envoyées dans processus.txt sous la forme de tableau par défaut et rien n'atteindra format-list. Il faut plutôt faire ainsi:

get-process | format-list | out-file processus.txt       

Si on désire écrire du texte dans un fichier (plutôt que d'envoyer le résultat d'une commande), on ne peut pas faire non plus:

write-host Tôt ce matin partons aux framboises | out-file paroles.txt             

Ceci créera bel et bien un fichier appelé paroles.txt, mais il sera vide! L'explication est simple: write-host envoie les données à la console et non pas dans le pipeline. Encore une fois, rien n'atteindra out-file. Mais pas d'inquiétude! PowerShell est plein de ressources et un applet de commande a été prévu pour ça! Il suffit d'utiliser write-output plutôt que write-host. write-output n'envoie pas le texte directement à la console, mais il l'envoie plutôt dans le pipeline vers la prochaine commande. (Notez que si write-output est la dernière commande, la sortie sera automatiquement redirigée à la console de toute façon.)

write-output Allons calmer toute notre faim | out-file paroles.txt -append             

Notez au passage le paramètre -append de out-file qui ajoute à la fin plutôt que d'écraser (le comportement par défaut). Notez également que rien n'atteint la console cette fois-ci!

Si vous regardez le fichier ainsi obtenu, vous constaterez qu'il ressemble à ceci:

Allons 
calmer      
toute      
notre      
faim      

write-output envoie un mot à la fois dans le pipeline, ce qui produit un fichier avec un mot par ligne... La solution? Utilisez les guillemets:

write-output "Puisqu'est venu mon invité splendide" | out-file paroles.txt -append             

Cette fois-ci, tout se retrouve bel et bien sur la même ligne.

Et pour vous simplifier encore plus la vie, l'alias write est créé par défaut et pointe vers write-output!

La lecture

Lire dans un fichier n'est pas beaucoup plus compliqué, en fin de compte. Il existe un applet de commande qui lit un fichier et retourne son contenu: get-content. Son paramètre -path permet de spécifier un fichier à lire. Supposons un fichier a.txt qui contient le texte suivant:

allo toi le jeune
comment vas-tu
Un deux un deux patate poil
Il était un petit navire       

La commande suivante va lire le fichier et écrit son contenu à l'écran:

get-content -path a.txt       

C'est bien joli, mais si tout ce qu'on peut faire est d'afficher le fichier à l'écran, on aurait aussi bien pu ouvrir le fichier dans le bloc-notes... Bien entendu, ça ne s'arrête pas là! On peut très bien envoyer le contenu dans une variable avec une simple assignation:

$fichier = get-content -path a.txt             

Du coup, on peut regarder le contenu de la variable:

$fichier             

On remarque que c'est le contenu complet du fichier, les quatre lignes l'une en dessous de l'autre. Ça ressemble étrangement à une variable de type "tableau", comme lorsque l'on fait:

$variable=1, 2, 3, 4             

On peut donc tester ceci pour voir:

$fichier[1]             

La deuxième ligne nous apparaît, confirmant qu'effectivement la variable contient un tableau, avec une ligne dans chaque case. Merveilleux! Pourquoi? Parce que qui dit tableau dit foreach! On pourra donc aisément parcourir le contenu du fichier une ligne à la fois:

$fichier = get-content -path a.txt
$compteurLigne = 1
foreach ($ligne in $fichier)
{
   write-host Ligne $compteurLigne :
   write-host $ligne
   $compteurLigne++
}

Ce qui serait encore plus intéressant, ça serait de pouvoir accéder au contenu mot par mot... Ça permettrait assez facilement de stocker une petite base de données dans un fichier (un enregistrement par ligne, un champ après l'autre, séparés par des espaces). Pour ce faire, rien de plus simple: notre $fichier[0] est en fait un string. Un string dans l'environnement .NET contient tout un tas de méthodes pratiques pour le manipuler. Celle qui nous intéresse ici est split. On lui passe un caractère devant être considéré comme un séparateur et le string se sépare en différents mots, qui nous sont encore une fois retournés sous forme de tableau. On peut donc utiliser un autre foreach (à l'intérieur du premier) pour passer à travers tous les mots de chaque ligne :

$fichier = get-content -path a.txt
$compteurLigne = 1
foreach ($ligne in $fichier)
{
   write-host Ligne $compteurLigne :
   $mots = $ligne.split(" ")
   $compteurMot = 1
   foreach ($mot in $mots)
   {
      write-host "  Mot $compteurMot : $mot"
      $compteurMot++
   }
   $compteurLigne++      
}

Observons maintenant le résultat pour la ligne 2:

Mot 1: comment
Mot 2: vas-tu

Évidemment, comme le split sépare les mots à partir des espaces, "vas-tu" est considéré comme un seul mot. Toutefois, il est possible de passer à split un tableau de séparateurs qui seront tous utilisés. On pourrait modifier notre script afin de séparer aussi avec des "-":

$fichier = get-content -path a.txt
$separateurs = " ", "-"
$compteurLigne = 1
foreach ($ligne in $fichier)
{
   write-host Ligne $compteurLigne :
   $mots = $ligne.split($separateurs)
   $compteurMot = 1
   foreach ($mot in $mots)
   {
      write-host "  Mot $compteurMot : $mot"
      $compteurMot++
   }
   $compteurLigne++      
}

Il est possible de mettre autant de séparateurs que désiré dans une variable.

Deux exercices

Voyez les solutions de ces exercices ici.

1- Créez un petit bottin téléphonique dans un fichier texte, en utilisant le format suivant:

Prénom Nom Numéro_de_téléphone
Prénom Nom Numéro_de_téléphone
...

Pour éviter les problèmes, assurez-vous que les prénoms, les noms de famille et les numéros ne contiennent pas d'espaces. Entrez quelques enregistrements fictifs (au moins 4).

Créez ensuite un script qui demande à l'usager d'entrer un prénom, puis un nom (deux demandes séparées). Le script doit aller lire votre fichier de bottin et trouver l'entrée qui correspond. S'il la trouve, il doit afficher le numéro correspondant. S'il ne la trouve pas, il doit afficher un message indiquant que l'entrée est introuvable.

Vous aurez besoin pour y arriver de vous inspirer de mon exemple ci-haut. Voici la méthode que je vous suggère:

  1. Créez une variable et stockez-y le contenu du fichier de bottin.
  2. Demandez à l'usager vos deux questions et placez les réponses dans des variables différentes.
  3. Faites une boucle foreach pour parcourir le contenu de la variable créée en 1, une ligne à la fois.
    1. Pour chaque ligne, séparez-la en mots.
    2. Comparez les mots avec les valeurs entrées par l'usager en 2
    3. Si les valeurs correspondent, affichez le numéro et placez quelque chose dans une variable pour vous rappeler que vous avez trouvé!
  4. Si vous n'avez rien trouvé, affichez le message d'erreur.

Pour vous simplifier la vie, supposez qu'il n'y aura jamais deux noms identiques dans le bottin.

2- Bonus - Créez un script qui éliminera un nom de votre bottin! Il devra demander lui aussi un nom et un prénom à l'usager, puis il recréera le fichier de bottin en omettant la ligne correspondant aux informations données, l'éliminant ainsi du bottin.

Le fonctionnement sera très similaire au numéro 1. La seule différence sera à l'étape 3.3: si les valeurs ne correspondent pas, on réécrit la ligne dans le fichier. Si elles correspondent, on ne fait rien.

Faites bien attention: la première ligne que vous réécrivez devra écraser le fichier original, mais toutes les autres devront ajouter des lignes à la fin! Du coup, il serait sans doute une bonne idée de se créer une variable pour savoir si on est en train d'écrire la première ligne ou non...